0 位追蹤者

記錄

Yii 提供了一個強大的記錄框架,它具有高度可自訂性和可擴展性。使用此框架,您可以輕鬆地記錄各種訊息類型、過濾它們,並將它們收集在不同的目標中,例如檔案、資料庫、電子郵件。

使用 Yii 記錄框架包含以下步驟

  • 在程式碼中的各個位置記錄 日誌訊息
  • 在應用程式配置中配置 日誌目標,以過濾和匯出日誌訊息;
  • 檢查由不同目標匯出的已過濾日誌訊息(例如 Yii 除錯器)。

在本節中,我們將主要描述前兩個步驟。

記錄訊息

記錄日誌訊息就像呼叫以下其中一種日誌記錄方法一樣簡單

  • Yii::debug():記錄訊息以追蹤一段程式碼的執行方式。這主要用於開發用途。
  • Yii::info():記錄傳達一些有用資訊的訊息。
  • Yii::warning():記錄警告訊息,指出發生了一些意外情況。
  • Yii::error():記錄應盡快調查的致命錯誤。

這些日誌記錄方法以各種嚴重程度級別類別記錄日誌訊息。它們共享相同的函數簽名 function ($message, $category = 'application'),其中 $message 代表要記錄的日誌訊息,而 $category 是日誌訊息的類別。以下範例中的程式碼在預設類別 application 下記錄追蹤訊息

Yii::debug('start calculating average revenue');

資訊:日誌訊息可以是字串以及複雜資料,例如陣列或物件。日誌訊息的處理責任在於 日誌目標。預設情況下,如果日誌訊息不是字串,則會透過呼叫 yii\helpers\VarDumper::export() 將其匯出為字串。

為了更好地組織和過濾日誌訊息,建議您為每個日誌訊息指定適當的類別。您可以為類別選擇階層式命名方案,這將使 日誌目標 更容易根據其類別過濾訊息。一種簡單而有效的命名方案是將 PHP 魔術常數 __METHOD__ 用於類別名稱。這也是 Yii 核心框架程式碼中使用的做法。例如,

Yii::debug('start calculating average revenue', __METHOD__);

__METHOD__ 常數評估為常數出現的方法名稱(以完整類別名稱為前綴)。例如,如果上述程式碼行在此方法中呼叫,則它等於字串 'app\controllers\RevenueController::calculate'

資訊:上面描述的日誌記錄方法實際上是 log() 方法的捷徑,該方法屬於 logger 物件,後者是透過表達式 Yii::getLogger() 可存取的單例。當記錄了足夠的訊息或應用程式結束時,logger 物件將呼叫 訊息分派器,以將記錄的日誌訊息發送到已註冊的 日誌目標

日誌目標

日誌目標是 yii\log\Target 類別或其子類別的實例。它根據日誌訊息的嚴重程度級別和類別過濾日誌訊息,然後將它們匯出到某些媒介。例如,資料庫目標 將過濾後的日誌訊息匯出到資料庫表,而 電子郵件目標 將日誌訊息匯出到指定的電子郵件地址。

您可以透過在應用程式配置中透過 log 應用程式組件 配置它們,在應用程式中註冊多個日誌目標,如下所示

return [
    // the "log" component must be loaded during bootstrapping time
    'bootstrap' => ['log'],
    // the "log" component process messages with timestamp. Set PHP timezone to create correct timestamp
    'timeZone' => 'America/Los_Angeles',
    'components' => [
        'log' => [
            'targets' => [
                [
                    'class' => 'yii\log\DbTarget',
                    'levels' => ['error', 'warning'],
                ],
                [
                    'class' => 'yii\log\EmailTarget',
                    'levels' => ['error'],
                    'categories' => ['yii\db\*'],
                    'message' => [
                       'from' => ['log@example.com'],
                       'to' => ['admin@example.com', 'developer@example.com'],
                       'subject' => 'Database errors at example.com',
                    ],
                ],
            ],
        ],
    ],
];

注意:log 組件必須在 引導啟動 時載入,以便它可以及時將日誌訊息分派到目標。這就是為什麼它如上所示列在 bootstrap 陣列中的原因。

在上面的程式碼中,兩個日誌目標已在 yii\log\Dispatcher::$targets 屬性中註冊

  • 第一個目標選擇錯誤和警告訊息,並將它們儲存在資料庫表中;
  • 第二個目標選擇類別名稱以 yii\db\ 開頭的錯誤訊息,並透過電子郵件將它們發送到 admin@example.comdeveloper@example.com

Yii 隨附以下內建日誌目標。請參閱有關這些類別的 API 文件,以了解如何配置和使用它們。

在下文中,我們將描述所有日誌目標共有的功能。

訊息過濾

對於每個日誌目標,您可以配置其 levelscategories 屬性,以指定目標應處理哪些嚴重程度級別和類別的訊息。

levels 屬性接受一個陣列,其中包含以下一個或多個值

如果您未指定 levels 屬性,則表示目標將處理任何嚴重程度級別的訊息。

categories 屬性接受一個陣列,其中包含訊息類別名稱或模式。目標將僅處理其類別可以在此陣列中找到或符合其中一種模式的訊息。類別模式是以星號 * 結尾的類別名稱前綴。如果類別名稱以模式的相同前綴開頭,則類別名稱與類別模式匹配。例如,yii\db\Command::executeyii\db\Command::query 用作在 yii\db\Command 類別中記錄的日誌訊息的類別名稱。它們都符合模式 yii\db\*

如果您未指定 categories 屬性,則表示目標將處理任何類別的訊息。

除了使用 categories 屬性指定允許的類別之外,您還可以透過 except 屬性排除某些類別。如果訊息的類別在此屬性中找到或符合其中一種模式,則目標將 *不* 會處理它。

以下目標配置指定目標應僅處理類別名稱符合 yii\db\*yii\web\HttpException:* 的錯誤和警告訊息,但不包括 yii\web\HttpException:404

[
    'class' => 'yii\log\FileTarget',
    'levels' => ['error', 'warning'],
    'categories' => [
        'yii\db\*',
        'yii\web\HttpException:*',
    ],
    'except' => [
        'yii\web\HttpException:404',
    ],
]

資訊:當 HTTP 例外被 錯誤處理常式 捕獲時,將記錄錯誤訊息,類別名稱格式為 yii\web\HttpException:ErrorCode。例如,yii\web\NotFoundHttpException 將導致類別為 yii\web\HttpException:404 的錯誤訊息。

訊息格式化

日誌目標以特定格式匯出過濾後的日誌訊息。例如,如果您安裝了 yii\log\FileTarget 類別的日誌目標,您可能會在 runtime/log/app.log 檔案中找到類似於以下的日誌訊息

2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug

預設情況下,日誌訊息將由 yii\log\Target::formatMessage() 格式化如下

Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Text

您可以透過配置 yii\log\Target::$prefix 屬性來自訂此格式,該屬性接受一個 PHP 可呼叫物件,該物件傳回自訂訊息前綴。例如,以下程式碼配置日誌目標,以目前使用者 ID 作為每個日誌訊息的前綴(為了隱私原因,IP 位址和 Session ID 已移除)。

[
    'class' => 'yii\log\FileTarget',
    'prefix' => function ($message) {
        $user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
        $userID = $user ? $user->getId(false) : '-';
        return "[$userID]";
    }
]

除了訊息前綴之外,日誌目標還會在每批日誌訊息中附加一些上下文資訊。預設情況下,包含以下全域 PHP 變數的值:$_GET$_POST$_FILES$_COOKIE$_SESSION$_SERVER。您可以透過使用您想要日誌目標包含的全域變數名稱配置 yii\log\Target::$logVars 屬性來調整此行為。例如,以下日誌目標配置指定僅將 $_SERVER 變數的值附加到日誌訊息。

[
    'class' => 'yii\log\FileTarget',
    'logVars' => ['_SERVER'],
]

您可以將 logVars 配置為空陣列,以完全停用上下文資訊的包含。或者,如果您想實作自己的提供上下文資訊的方式,您可以覆寫 yii\log\Target::getContextMessage() 方法。

如果您的某些請求欄位包含您不想記錄的敏感資訊(例如密碼、存取權杖),您可以額外配置 maskVars 屬性。預設情況下,以下請求參數將使用 *** 遮罩:$_SERVER[HTTP_AUTHORIZATION]$_SERVER[PHP_AUTH_USER]$_SERVER[PHP_AUTH_PW],但您可以設定自己的參數

[
    'class' => 'yii\log\FileTarget',
    'logVars' => ['_SERVER'],
    'maskVars' => ['_SERVER.HTTP_X_PASSWORD']
]

訊息追蹤層級

在開發期間,通常希望查看每個日誌訊息的來源。這可以透過像以下這樣配置 log 組件的 traceLevel 屬性來實現

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [...],
        ],
    ],
];

如果 YII_DEBUG 為開啟,則上述應用程式配置將 traceLevel 設定為 3,如果 YII_DEBUG 為關閉,則設定為 0。這表示,如果 YII_DEBUG 為開啟,則每個日誌訊息最多會附加 3 個層級的呼叫堆疊,在該呼叫堆疊中記錄日誌訊息;如果 YII_DEBUG 為關閉,則不會包含呼叫堆疊資訊。

資訊:獲取呼叫堆疊資訊並非易事。因此,您僅應在開發期間或除錯應用程式時使用此功能。

訊息刷新與匯出

如前所述,日誌訊息由 logger 物件 維護在陣列中。為了限制此陣列的記憶體消耗,logger 將在陣列累積一定數量的日誌訊息時,將記錄的訊息刷新到 日誌目標。您可以透過配置 log 組件的 flushInterval 屬性來自訂此數字

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'flushInterval' => 100,   // default is 1000
            'targets' => [...],
        ],
    ],
];

資訊:訊息刷新也會在應用程式結束時發生,這確保日誌目標可以接收完整的日誌訊息。

logger 物件 將日誌訊息刷新到 日誌目標 時,它們不會立即匯出。相反,訊息匯出僅在日誌目標累積一定數量的過濾訊息時發生。您可以透過配置個別 日誌目標exportInterval 屬性來自訂此數字,如下所示,

[
    'class' => 'yii\log\FileTarget',
    'exportInterval' => 100,  // default is 1000
]

由於刷新和匯出級別設定,預設情況下,當您呼叫 Yii::debug() 或任何其他日誌記錄方法時,您將 *不會* 立即在日誌目標中看到日誌訊息。對於某些長時間執行的主控台應用程式,這可能是一個問題。為了使每個日誌訊息立即出現在日誌目標中,您應將 flushIntervalexportInterval 都設定為 1,如下所示

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'flushInterval' => 1,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'exportInterval' => 1,
                ],
            ],
        ],
    ],
];

注意:頻繁的訊息刷新和匯出會降低應用程式的效能。

切換記錄目標

您可以透過配置日誌目標的 enabled 屬性來啟用或停用它。您可以透過日誌目標配置或程式碼中的以下 PHP 語句來執行此操作

Yii::$app->log->targets['file']->enabled = false;

上述程式碼要求您將目標命名為 file,如下所示,透過在 targets 陣列中使用字串鍵

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'targets' => [
                'file' => [
                    'class' => 'yii\log\FileTarget',
                ],
                'db' => [
                    'class' => 'yii\log\DbTarget',
                ],
            ],
        ],
    ],
];

自 2.0.13 版起,您可以將 enabled 配置為可呼叫物件,以定義日誌目標是否應啟用的動態條件。有關範例,請參閱 yii\log\Target::setEnabled() 的文件。

建立新目標

建立新的日誌目標類別非常簡單。您主要需要實作 yii\log\Target::export() 方法,將 yii\log\Target::$messages 陣列的內容傳送到指定的媒介。您可以呼叫 yii\log\Target::formatMessage() 方法來格式化每個訊息。如需更多詳細資訊,您可以參閱 Yii 版本中包含的任何日誌目標類別。

提示:您可以嘗試使用任何 PSR-3 相容的日誌記錄器,例如 Monolog,而不是建立自己的日誌記錄器,方法是使用 PSR 日誌目標擴展

效能分析

效能分析是一種特殊的訊息日誌記錄類型,用於測量某些程式碼區塊所花費的時間,並找出效能瓶頸是什麼。例如,yii\db\Command 類別使用效能分析來找出每個資料庫查詢所花費的時間。

若要使用效能分析,請先識別需要分析的程式碼區塊。然後像以下這樣將每個程式碼區塊括起來

\Yii::beginProfile('myBenchmark');

...code block being profiled...

\Yii::endProfile('myBenchmark');

其中 myBenchmark 代表識別程式碼區塊的唯一權杖。稍後當您檢查效能分析結果時,您將使用此權杖來定位相應程式碼區塊所花費的時間。

務必確保 beginProfileendProfile 的配對正確巢狀。例如,

\Yii::beginProfile('block1');

    // some code to be profiled

    \Yii::beginProfile('block2');
        // some other code to be profiled
    \Yii::endProfile('block2');

\Yii::endProfile('block1');

如果您遺漏 \Yii::endProfile('block1') 或切換 \Yii::endProfile('block1')\Yii::endProfile('block2') 的順序,則效能分析將無法運作。

對於正在分析的每個程式碼區塊,都會記錄嚴重程度級別為 profile 的日誌訊息。您可以配置 日誌目標 來收集此類訊息並匯出它們。Yii 除錯器 具有內建的效能分析面板,顯示效能分析結果。

發現錯字或您認為此頁面需要改進嗎?
在 github 上編輯它 !